/* 
 * File:   DTAMesh.h
 * Author: fozut
 *
 * Created on 22 de Dezembro de 2009, 14:32
 */

#ifndef _DTAMESH_H
#define	_DTAMESH_H

#include "DTAHash.h"
#include "DTATriangulo.h"
#include "DTAPonto.h"
#include "DTALinkedList.h"



class DTAMeshTriangle;
class DTAMeshPoint;


class DTAMeshTriangle:public DTATriangulo
{
public:
   // DTAHash<DTAPonto>::HashNode* ref;
    const DTAMeshPoint* ptrp1;
    const DTAMeshPoint* ptrp2;
    const DTAMeshPoint* ptrp3;
    DTALinkedList<const DTAHash<DTAMeshPoint>::HashNode*> *ref;

    void operator = (DTATriangulo tr)
    {
        this->active = tr.active;
        this->id = tr.active;
        this->p1 = tr.p1;
        this->p2 = tr.p2;
        this->p3 = tr.p3;        
    };
};

class DTAMeshPoint:public DTAPonto
{
public:   
    DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *ref;
    void operator = (DTAPonto pt)
    {
        this->active = pt.active;
        this->id = pt.id;
        this->x = pt.x;
        this->y = pt.y;
        this->z = pt.z;
    };
};













class DTATriMesh
{
public:
    typedef DTAHash<DTAMeshTriangle>::HashNode MeshCell;

    DTATriMesh();
    ~DTATriMesh();
    const DTAHash<DTAMeshTriangle>::HashNode *addCell(DTATriangulo tr);
    void removeCell(DTATriangulo tr);
    //const DTAHash<DTATriangulo>::HashNode *alterCell(DTATriangulo oldTr, DTATriangulo newTr);
    void alterPoint(DTAPonto oldPt, DTAPonto newPt);
    DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*>* getTriangles(DTAPonto pt);
    DTALinkedList<DTATriangulo>* getVizinhos(DTATriangulo tr);
    bool findTriangles(DTATriangulo tr);
    bool findPoint(DTAPonto pt);


    void lalala();
private:
    DTAHash<DTAMeshPoint> *DHashPt;
    DTAHash<DTAMeshTriangle> *DHashTr;
    
};


DTATriMesh::DTATriMesh()
{
    DHashPt = new DTAHash<DTAMeshPoint>;
    DHashTr = new DTAHash<DTAMeshTriangle>;
};


DTATriMesh::~DTATriMesh()
{
   // delete DHashPt;
   // delete DHashTr;
};


void DTATriMesh::lalala()
{
    cout << "Hash do triangulo" << endl;
    DHashTr->printHashHeight();
    
    cout << "Hash do ponto" << endl;
    DHashPt->printHashHeight();
}

const DTAHash<DTAMeshTriangle>::HashNode* DTATriMesh::addCell(DTATriangulo tr)
{   

    //Converte um ponto comum num ponto da malha;
    //O ponto é convertido pois é necessário armazenar a informacao aa qual triangulo ele pertence, de modo a podermos
    //ter relacoes topologicas na malha
    DTAMeshPoint MpPoint1;
    DTAMeshPoint MpPoint2;
    DTAMeshPoint MpPoint3;

    MpPoint1 = tr.p1;
    //MpPoint1.ref = new  DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*>;

    MpPoint2 = tr.p2;
    //MpPoint2.ref = new  DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*>;

    MpPoint3 = tr.p3;
    //MpPoint3.ref = new  DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*>;

    //Adiciona os tres pontos convertidos em MeshPoint no hash; note que nao eh neceesario reimplementar
    //o método toHash, devido aa mesma, herdar os atributos e metodos de DTAPonto
    const DTAHash<DTAMeshPoint>::HashNode* ptrMpPoint1;
    const DTAHash<DTAMeshPoint>::HashNode* ptrMpPoint2;
    const DTAHash<DTAMeshPoint>::HashNode* ptrMpPoint3;

    if( DHashPt->findData(MpPoint1) == false) //procura se o ponto ja foi ensrido na malha; se nao, aloca uma nova lista encadeada para armazenar a referencia a triangulos
    {
        MpPoint1.ref = new  DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*>;
        ptrMpPoint1 = DHashPt->addData(MpPoint1);
    }
     else
        ptrMpPoint1 = DHashPt->alterProperty(MpPoint1);

    if( DHashPt->findData(MpPoint2) == false)
    {
        MpPoint2.ref = new  DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*>;
        ptrMpPoint2 = DHashPt->addData(MpPoint2);
    }
     else
        ptrMpPoint2 = DHashPt->alterProperty(MpPoint2);

    if( DHashPt->findData(MpPoint3) == false)
    {
        MpPoint3.ref = new  DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*>;
        ptrMpPoint3 = DHashPt->addData(MpPoint3);
    }
    else
        ptrMpPoint3 = DHashPt->alterProperty(MpPoint3);

    
    
    

    //Com os pontos adicionados e os seus ponteiros recebidos, devemos cria um novo triangulo na malha
    //de modo que os pontos do triangulo façam referencia aa posicoes dos pontos armazenados na hash.
    //Como os ponteiros dos pontos sao do 'tipo const', as informacoes apenas podem ser lidas, garantindo a
    //integridade da estrutura sem afetar a logica das relacoes topologicas (pois utilizam apenas leitura e
    //nao escrita dos pontos)
    DTAMeshTriangle MtTriangle;
    //MtTriangle.ref = new   DTALinkedList<const DTAHash<DTAMeshPoint>::HashNode*>;
    const DTAHash<DTAMeshTriangle>::HashNode* ptrMtTriangle;
    ptrMtTriangle = NULL;



    MtTriangle = tr;

    if( DHashTr->findData(MtTriangle) == false) // o triangulo nao esta presente na estrutura
    {
        MtTriangle.ref = new   DTALinkedList<const DTAHash<DTAMeshPoint>::HashNode*>;

        MtTriangle.getIncentro(); //força que o incentro seja calculado antes de ser inserido

        MtTriangle.ref->addData(ptrMpPoint1);
        MtTriangle.ref->addData(ptrMpPoint2);
        MtTriangle.ref->addData(ptrMpPoint3);


        ptrMtTriangle = DHashTr->addData(MtTriangle);

        DHashPt->alterProperty(MpPoint1)->data.ref->addData(ptrMtTriangle);
        DHashPt->alterProperty(MpPoint2)->data.ref->addData(ptrMtTriangle);
        DHashPt->alterProperty(MpPoint3)->data.ref->addData(ptrMtTriangle);

    }
    else
        ptrMtTriangle = DHashTr->alterProperty(MtTriangle);


   

    return ptrMtTriangle;       
};



void DTATriMesh::removeCell(DTATriangulo tr)
{
    DTAMeshTriangle mTtr;
    DTAMeshPoint mPp1;
    DTAMeshPoint mPp2;
    DTAMeshPoint mPp3;
    const DTAHash<DTAMeshTriangle>::HashNode* ptrMtTr;

    mTtr = tr;

    if( DHashTr->findData(mTtr) == true)
    {
        cout << "continuando a remocao da celula em DTATriMesh" << endl;
        ptrMtTr = DHashTr->alterProperty(mTtr); //pega o ponteiro à celula na estrutura
        
        
        //remove dos pontos as ocorrencias da célula
       // DHashPt->alterProperty();
        mPp1 = ptrMtTr->data.p1;
      //  mPp1.print();
        mPp2 = ptrMtTr->data.p2;
      //  mPp2.print();
        mPp3 = ptrMtTr->data.p3;
     //   mPp3.print();

       // cout << DHashPt->findData(mPp1) << endl;
        DTAHash<DTAMeshPoint>::HashNode* meshpointP1 = DHashPt->alterProperty(mPp1);        
        meshpointP1->data.ref->removeData(ptrMtTr);

       // cout << DHashPt->findData(mPp2) << endl;
        DTAHash<DTAMeshPoint>::HashNode* meshpointP2 = DHashPt->alterProperty(mPp2);
        meshpointP2->data.ref->removeData(ptrMtTr);

       // cout << DHashPt->findData(mPp3) << endl;
        DTAHash<DTAMeshPoint>::HashNode* meshpointP3 = DHashPt->alterProperty(mPp3);
        meshpointP3->data.ref->removeData(ptrMtTr);

        //remove a celula da estrutura
        DHashTr->removeData(mTtr);       
    }
    else
    {
        cout << "Erro de processamento em DTATriMesh - metodo RemoveCell - triangulo nao existe na estrutura" << endl;
    }
};




void DTATriMesh::alterPoint(DTAPonto oldPt, DTAPonto newPt)
{
    register int i;
    DTAMeshPoint MpPt, newMpPt;
    DTAMeshTriangle auxMtTr;
    MpPt = oldPt;
    newMpPt = newPt;
    DTALinkedList<DTAMeshTriangle> *trianglesToUpdate = new DTALinkedList<DTAMeshTriangle>;

    cout << "procura do oldPoint em alterPoint: " << DHashPt->findData(MpPt)<<endl;

    if(DHashPt->findData(MpPt) == true)
    {
        //pega a lista de triangulos ao qual o ponto pertence
        DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *listTrPt = DHashPt->alterProperty(MpPt)->data.ref;

        cout << "numeros de triangulos pertencentes ao oldPoint: " << listTrPt->getNumReg() << endl;
        for(i=0; i<listTrPt->getNumReg();i++) //para o primeiro ponto, armazena quais os triangulos que devem ser alterados
        {
            const DTAHash<DTAMeshTriangle>::HashNode *auxNode = *(listTrPt->getData(i)); //pega cada triangulo que o ponto faz parte
            auxMtTr = auxNode->data;
            trianglesToUpdate->addData(auxMtTr); //obtem a lista de triangulos ao qual o ponto pertence
        }
        
        DTAMeshTriangle aauxTr;
        for(i=0;i<trianglesToUpdate->getNumReg();i++)
        {
           aauxTr = *(trianglesToUpdate->getData(i));
           aauxTr.print();
        }
        
       
        
        //remove os antigos triangulos
        for(i=0;i<trianglesToUpdate->getNumReg();i++)
        {
            aauxTr = *(trianglesToUpdate->getData(i));
            removeCell(aauxTr); //remove o triangulo da malha
            //atualiza o ponto que mudou no triangulo
            trianglesToUpdate->findPointer(*(trianglesToUpdate->getData(i)))->data.alterPoint(oldPt,newPt);
        }

         for(i=0;i<trianglesToUpdate->getNumReg();i++)
        {
           aauxTr = *(trianglesToUpdate->getData(i));
           aauxTr.print();
        }
        
        //insere novamente os trinagulos na malha, sendo que eles ja foram atualizados.
        for(i=0;i<trianglesToUpdate->getNumReg();i++)
        {
            addCell(*(trianglesToUpdate->getData(i)));
        }
        

         //atualiza o ponto no Hash de pontos
        DHashPt->removeData(MpPt);
        DHashPt->addData(newMpPt);
    }
    
}


DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*>* DTATriMesh::getTriangles(DTAPonto pt)
{
    DTAMeshPoint Mp;
    Mp = pt;

    return DHashPt->alterProperty(Mp)->data.ref;
}



DTALinkedList<DTATriangulo>* DTATriMesh::getVizinhos(DTATriangulo tr)
{
    DTALinkedList<DTATriangulo> *ret = NULL;
    DTATriangulo trRet;
    DTAMeshTriangle mt; //Triangulo da malha

    DTAMeshPoint mPp1; //ponto da malha; ja deve estar inserido
    DTAMeshPoint mPp2; //ponto da malha; ja deve estar inserido
    DTAMeshPoint mPp3; //ponto da malha; ja deve estar inserido

    bool buscaTriangulo; //resultado da busca por um triangulo na malha; se o triangulo ja estiver inserido o processamento continua, caso contrario, nao.
    bool buscaP1;
    bool buscaP2;    
    bool buscaP3;

    DTALinkedList<DTAMeshTriangle> DLinkedMTriangle; //armazena todos os triangulos que sao
    register int i,j;

    tr.getIncentro(); //obriga o calculo do incentro do triangulo

    //atribuicao de valores aas variaveis do metodo
    mt = tr;
    mPp1 = tr.p1;
    mPp2 = tr.p2;
    mPp3 = tr.p3;
    buscaTriangulo = false;

    

    buscaTriangulo = DHashTr->findData(mt); //procura o triangulo na malha

    if(buscaTriangulo == true) // o triangulo existe
    {
        //cout << "Triangulo na estrutura - Classe DTATriMesh" <<endl;
        //procura se os pontos estao instanciados na classe
        buscaP1 = DHashPt->findData(mPp1);
        buscaP2 = DHashPt->findData(mPp2);
        buscaP3 = DHashPt->findData(mPp3);



        if(buscaP1 == true && buscaP2 == true && buscaP3 == true) //se os pontos estiverem presentes na classe, continua o processamento
        {
            //cout << "Pontos encontrados em DTATriMesh; continuando processamento em DTATriMesh" << endl;

            DTAHash<DTAMeshPoint>::HashNode* ptrMpP1 = DHashPt->alterProperty(mPp1);
            DTAHash<DTAMeshPoint>::HashNode* ptrMpP2 = DHashPt->alterProperty(mPp2);
            DTAHash<DTAMeshPoint>::HashNode* ptrMpP3 = DHashPt->alterProperty(mPp3);
            DTAHash<DTAMeshTriangle>::HashNode* ptrMtTriangle = DHashTr->alterProperty(mt);
            ret = new DTALinkedList<DTATriangulo>;

            //ptrMpP1->data.ref->printDataFolha();
            //ptrMpP2->data.ref->printDataFolha();
            //ptrMpP3->data.ref->printDataFolha();

            //descobrimos as relacoes de vizinhanca de acordo com a relacao de pertence entre os pontos e triangulos:
            //uma vez que cada ponto guarda uma lista de triangulos a que pertence, basta percorrer os pontos 2 a 2
            //verificando quais sao os ponteiros para os triangulos que sao iguais em cada lista de referencia, excluindo o
            //triangulo ao qual os vizinhos sao buscados (parametro do metodo).

            //compara as listas de referencia do primeiro e do segundo ponto
            //cout << "num reg em mpP1 = " << ptrMpP1->data.ref->getNumReg() << endl;
            //cout << "num reg em mpP2 = " << ptrMpP2->data.ref->getNumReg() << endl;
            for(i=0;i<ptrMpP1->data.ref->getNumReg();i++)
            {
                for(j=0;j<ptrMpP2->data.ref->getNumReg();j++)
                {
                     DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *trOfP1 = ptrMpP1->data.ref; //lista de triangulos pertencentes ao ponto 1
                     DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *trOfP2 = ptrMpP2->data.ref; //lista de triangulos pertecncentes ao ponto 2



                    
                    //pega os dados de cada lista encadeada, comparando os ponteiros
                    const DTAHash<DTAMeshTriangle>::HashNode*  hPtr = *(trOfP1->getData(i));
                    const DTAHash<DTAMeshTriangle>::HashNode*  hhPtr = *(trOfP2->getData(j));
                    //cout << "comparando: " << hPtr << " " << hhPtr << endl;

                    if( hPtr == hhPtr) //se os ponteiros sao iguais, entao temos uma relacao de vizinhanca
                    {
                       // cout << "Tem triangulo igual em DTATriMesh IOW - Pontos 1 e 2" << endl;
                        trRet.p1 = hPtr->data.p1;
                        trRet.p2 = hPtr->data.p2;
                        trRet.p3 = hPtr->data.p3;
                        if( ret->findData(trRet) == false && trRet != tr)
                            ret->addData(trRet);
                    }
                 
                }
            }

            //compara as listas de referencia do segundo  e do terceiro ponto
            //cout << "num reg em mpP2 = " << ptrMpP2->data.ref->getNumReg() << endl;
            //cout << "num reg em mpP3 = " << ptrMpP3->data.ref->getNumReg() << endl;
            for(i=0;i<ptrMpP2->data.ref->getNumReg();i++)
            {
                for(j=0;j<ptrMpP3->data.ref->getNumReg();j++)
                {
                     DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *trOfP1 = ptrMpP2->data.ref;
                     DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *trOfP2 = ptrMpP3->data.ref;





                    const DTAHash<DTAMeshTriangle>::HashNode* hPtr = *(trOfP1->getData(i));
                    const DTAHash<DTAMeshTriangle>::HashNode* hhPtr = *(trOfP2->getData(j));
                   // cout << "comparando: " << hPtr << " " << hhPtr << endl;
                    if( hPtr == hhPtr)
                    {
                        //cout << "Tem triangulo igual em DTATriMesh IOW - Pontos 2 e 3" << endl;
                        trRet.p1 = hPtr->data.p1;
                        trRet.p2 = hPtr->data.p2;
                        trRet.p3 = hPtr->data.p3;
                        if( ret->findData(trRet) == false  && trRet != tr)
                            ret->addData(trRet);
                    }

                }
            }

            //compara as listas de referencia do terceiro e do primeiro ponto
            //cout << "num reg em mpP1 = " << ptrMpP1->data.ref->getNumReg() << endl;
            //cout << "num reg em mpP3 = " << ptrMpP3->data.ref->getNumReg() << endl;
            for(i=0;i<ptrMpP1->data.ref->getNumReg();i++)
            {
                for(j=0;j<ptrMpP3->data.ref->getNumReg();j++)
                {
                     DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *trOfP1 = ptrMpP1->data.ref;
                     DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *trOfP2 = ptrMpP3->data.ref;





                    const DTAHash<DTAMeshTriangle>::HashNode* hPtr = *(trOfP1->getData(i));
                    const DTAHash<DTAMeshTriangle>::HashNode* hhPtr = *(trOfP2->getData(j));
                   // cout << "comparando: " << hPtr << " " << hhPtr << endl;
                    if( hPtr == hhPtr)
                    {
                        //cout << "Tem triangulo igual em DTATriMesh IOW - Pontos 1 e 3" << endl;
                        trRet.p1 = hPtr->data.p1;
                        trRet.p2 = hPtr->data.p2;
                        trRet.p3 = hPtr->data.p3;
                        if( ret->findData(trRet) == false  && trRet != tr)
                            ret->addData(trRet);
                    }

                }
            }
            

        }
        else //senao nao
        {
            cout << "Erro no processamento em DTATriMesh - algum ponto nao foi encontrado; porém a celula foi encontrada" << endl;
        }

        
    }
    else //se a celula nao existir na estrutura, o processamento eh cancelado
    {
        cout << "Triangulo fora da estrutura"<<endl;
    }

    return ret;
}


bool DTATriMesh::findTriangles(DTATriangulo tr)
{
    tr.getIncentro();
    DTAMeshTriangle mt1;
   
    mt1=tr;
    mt1.getIncentro();   
   return DHashTr->findData((mt1)) ;
}


bool DTATriMesh::findPoint(DTAPonto pt)
{
    DTAMeshPoint mpt;
    mpt= pt;

    return DHashPt->findData(mpt);
}
#endif	/* _DTAMESH_H */

/*const DTAHash<DTATriangulo>::HashNode* DTATriMesh::alterCell(DTATriangulo oldTr, DTATriangulo newTr)
{
    register int i;
    DTAMeshTriangle mtTr, auxMtTr;
    DTALinkedList<DTAMeshTriangle> *trianglesToUpdate = new DTALinkedList<DTAMeshTriangle>;

    DTAMeshPoint MpP1; //ponto para ser buscado na hash que armazena os pontos da malha
    DTAMeshPoint MpP2; //ponto para ser buscado na hash que armazena os pontos da malha
    DTAMeshPoint MpP3; //ponto para ser buscado na hash que armazena os pontos da malha

    //atribui os pontos do triangulo antigo, afim de buscarmos ele na malha
    MpP1= oldTr.p1;
    MpP2= oldTr.p2;
    MpP3= oldTr.p3;
    mtTr = oldTr;




    if( DHashTr->findData(mtTr) == true) //procura se o triangulo esta armazenado na etsrutura
    {
        //Para cada ponto armazenado na estrutura, obtem a lista de triangulos que ele esta contido
        DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *listTrP1 = DHashPt->alterProperty(MpP1)->data.ref;
        DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *listTrP2 = DHashPt->alterProperty(MpP2)->data.ref;
        DTALinkedList<const DTAHash<DTAMeshTriangle>::HashNode*> *listTrP3 = DHashPt->alterProperty(MpP3)->data.ref;


        //cout << listTrP1->getNumReg() << endl;
        //cout << listTrP2->getNumReg() << endl;
        //cout << listTrP3->getNumReg() << endl;

//        for(i=0; i<listTrP1->getNumReg();i++)
//        {
//            const DTAHash<DTAMeshTriangle>::HashNode *auxNode = *(listTrP1->getData(i));
//            mtTr = auxNode->data;
//            mtTr.print();
//        }
//
//         for(i=0; i<listTrP2->getNumReg();i++)
//        {
//            const DTAHash<DTAMeshTriangle>::HashNode *auxNode = *(listTrP2->getData(i));
//            mtTr = auxNode->data;
//            mtTr.print();
//        }
//
//         for(i=0; i<listTrP3->getNumReg();i++)
//        {
//            const DTAHash<DTAMeshTriangle>::HashNode *auxNode = *(listTrP3->getData(i));
//            mtTr = auxNode->data;
//            mtTr.print();
//        }
//
       // if()
        for(i=0; i<listTrP1->getNumReg();i++) //para o primeiro ponto, armazena quais os triangulos que devem ser alterados
        {
           // cout << listTrP1->getNumReg() << endl;
            const DTAHash<DTAMeshTriangle>::HashNode *auxNode = *(listTrP1->getData(i)); //pega cada triangulo que o ponto faz parte
            auxMtTr = auxNode->data;
            trianglesToUpdate->addData(auxMtTr); //adiciona o triangulo a lista de triangulos que devem ser atualizados
        }

        for(i=0; i<listTrP2->getNumReg();i++) //para o segundo ponto, armazena quais os triangulos que devem ser alterados
        {
            const DTAHash<DTAMeshTriangle>::HashNode* auxNode = *(listTrP2->getData(i)); //pega cada triangulo que o ponto faz parte
            auxMtTr = auxNode->data;
            if( trianglesToUpdate->findData(auxMtTr) == false) //se o triangulo ja nao esta na lista, entao armazena-o
                trianglesToUpdate->addData(auxMtTr);//adiciona o triangulo a lista de triangulos que devem ser atualizados
        }

        for(i=0; i<listTrP3->getNumReg();i++) //para o terceiro ponto, armazena quais os triangulos que devem ser alterados
        {
            const DTAHash<DTAMeshTriangle>::HashNode* auxNode = *(listTrP3->getData(i));//pega cada triangulo que o ponto faz parte
            auxMtTr = auxNode->data;
            if( trianglesToUpdate->findData(auxMtTr) == false) //se o triangulo ja nao esta na lista, entao armazena-o
                trianglesToUpdate->addData(auxMtTr);//adiciona o triangulo a lista de triangulos que devem ser atualizados
        }

        for(i=0;i<trianglesToUpdate->getNumReg();i++)
        {
            auxMtTr = *(trianglesToUpdate->getData(i));
            auxMtTr.print();
        }

    }
    else
    {
        cout << "erro em DTATriMesh: o método alterCell; triangulo nao encontrado" << endl;
    }
};
*/


